/*
 * Compile with:
 * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
 */

#include <sys/types.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#else
#include <windows.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event.h>
#include <iostream>
using namespace std;

void connection_timeout(int fd, short event, void *arg_)
{
	struct event *arg = reinterpret_cast<struct event *>(arg_);
#ifdef WIN32
	shutdown(fd, SD_BOTH);
#else
	close(fd);
#endif
	free(arg);
}
void on_read(char *buf, int count)
{
	cout << "on_read" << endl;
}
void connection_read(int fd, short event, void *arg)
{
	struct event *ev = reinterpret_cast<struct event *>(arg);
	char buf[1024];
	int count = recv(fd, buf, sizeof(buf), 0);
	cout << "fd " << fd << "recv " << count << endl;
	if (count < 1) {
		cout << "disconnect" << endl;
		free(arg);
		close(fd);
	} else {
		while(count > 0) {
			on_read(buf, count);
			count = recv(fd, buf, sizeof(buf), 0);
		}
		event_add(ev, NULL);
	}
}
void connection_write(int fd, short event, void *arg_)
{
	struct event *arg = reinterpret_cast<struct event *>(arg_);
	time_t now;
	
	time(&now);
	int len;
#ifdef WIN32
	struct tm *t = localtime(&now);
	char *buf = asctime(t);
	len = strlen(buf);
#else
	char buf[32];
	struct tm t;
	localtime_r(&now, &t);
	asctime_r(&t, buf);
	len = strlen(buf);
#endif

	write(fd, buf, len);

	/* for debugging */
	fprintf(stderr, "%s(): fd = %d, event = %d.\n", __func__, fd, event);
}

void connection_accept(int fd, short event, void *arg)
{
	/* Accept a new connection. */
	struct sockaddr_in s_in;
	#ifdef WIN32
	int len = sizeof(s_in);
	#else
	socklen_t len = sizeof(s_in);
	#endif
	int sock = accept(fd, (struct sockaddr *)&s_in, &len);
	if (sock < 0) {
		perror("accept");
		return;
	}
	cout << "fd : " << sock << endl;
	
	/* Install time server. */
	struct event *ev = reinterpret_cast<struct event *>(malloc(sizeof(struct event)));
	/*
	event_set(ev, sock, EV_WRITE, connection_write, ev);
	event_add(ev, NULL);
	ev = reinterpret_cast<struct event *>(malloc(sizeof(struct event)));
	*/
	event_set(ev, sock, EV_READ, connection_read, ev);
	event_add(ev, NULL);
	/*
	ev = reinterpret_cast<struct event *>(malloc(sizeof(struct event)));
	event_set(ev, sock, EV_TIMEOUT, connection_timeout, ev);
	event_add(ev, NULL);
	*/
}
int main (int argc, char **argv)
{
	struct event evfifo;
	int sockfd;
#ifdef WIN32
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	  
	wVersionRequested = MAKEWORD( 2, 0 );
	err = WSAStartup(wVersionRequested, &wsaData);
	/* Confirm that the WinSock DLL supports 2.0.*/
	/* Note that if the DLL supports versions greater    */
	/* than 2.0 in addition to 2.0, it will still return */
	/* 2.0 in wVersion since that is the version we      */
	/* requested.                                        */	 
	if (err != 0 || LOBYTE( wsaData.wVersion ) != 2 ||
	        HIBYTE( wsaData.wVersion ) != 0 ) {
	    /* Tell the user that we couldn't find a usable */
	    /* WinSock DLL.                                  */
	    WSACleanup();
	    perror("couldn't find WinSock2 dll");
	    return 0; 
	}
#endif	
	
	struct sockaddr_in serv;
	/*initial server socket*/ 
	memset(&serv,0,sizeof(serv));
	serv.sin_family=AF_INET;
	serv.sin_port=htons(40003);
	serv.sin_addr.s_addr=htonl(INADDR_ANY); //inet_addr("192.168.15.25");
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd==-1) 
	{ 
		perror("sockfd");
		return 0;
	} 
	if (bind(sockfd,(struct sockaddr *)&serv,sizeof(serv))==-1) 
	{ 
		perror("bind");
		return 0;
	} 
	if (listen(sockfd,1024)==-1) 
	{ 
		perror("listen");
		return 0;
	} 
	/* Initalize the event library */ 
	event_init();
	event_set(&evfifo, sockfd, EV_READ | EV_PERSIST, connection_accept, &evfifo);
	/* Add it to the active events, without a timeout */ 
	event_add(&evfifo, NULL);
	cout << "event_dispatch" << endl;
	event_dispatch();
	close(sockfd); 
#ifdef WIN32
	    WSACleanup();
#endif
	return 0;
}

